import os
import requests
from flask import request, jsonify, send_from_directory
from fsrs import Scheduler, Card as FSRSCard, State
from loguru import logger
from json import dumps
from datetime import datetime, timezone, timedelta
from .models import Card, ReviewLog, db


scheduler = Scheduler(desired_retention=float(os.environ.get("DESIRED_RETENTION", 0.9)))


def register_routes(app):
    @app.route("/api/config")
    def get_config():
        return open("config.json", encoding="utf-8").read()

    @app.route("/api/add_cards", methods=["POST"])
    def add_cards():
        """
        添加批量卡片接口
        ---
        请求方法: POST
        请求体参数:
          - grade: string 必填，年级分类
          - subject: string 必填，学科分类
          - class_names: array 必填，班级名称列表
          - cards: array 必填，卡片对象数组
            - question: string 必填，问题内容
            - answer: string 可选，答案内容

        响应结构:
        成功(201):
        {
          "added": 添加数量,
          "cards": [{"id", "grade", "subject", "class_name"}],
          "fsrs_params": {"stability", "difficulty", "state"}
        }
        错误(400):
        {"error": "缺少必要字段"}
        """

        required_fields = ["grade", "subject", "class_names", "cards"]
        if not all(field in request.json for field in required_fields):
            return (
                jsonify({"error": "缺少必要字段: grade, subject, class_names 或 cards"}),
                400,
            )
        logger.info(dumps(request.json))
        grade = request.json["grade"]
        subject = request.json["subject"]
        class_names = request.json["class_names"]
        cards_data = request.json["cards"]

        new_cards = []
        for class_name in class_names:
            for card_data in cards_data:
                fsrs_card = FSRSCard()
                new_card = Card(
                    grade=grade,
                    subject=subject,
                    class_name=class_name,
                    question=card_data["question"],
                    answer=card_data.get("answer", ""),
                    due=datetime.now(timezone.utc),
                    stability=fsrs_card.stability,
                    difficulty=fsrs_card.difficulty,
                    state=fsrs_card.state.value,
                    last_review=fsrs_card.last_review,
                )
                new_fsrs_card, review_log = scheduler.review_card(new_card.to_fsrs(), 3)
                new_card.due = new_fsrs_card.due
                new_card.stability = new_fsrs_card.stability
                new_card.difficulty = new_fsrs_card.difficulty
                new_card.state = 2
                new_card.last_review = review_log.review_datetime
                db.session.add(new_card)
                db.session.flush()  # 获取新卡片的ID
                new_cards.append(
                    {
                        "id": new_card.id,
                        "grade": grade,
                        "subject": subject,
                        "class_name": class_name,
                    }
                )

        db.session.commit()
        response_data = {
            "added": len(new_cards),
            "cards": new_cards,
            "fsrs_params": {
                "stability": fsrs_card.stability,
                "difficulty": fsrs_card.difficulty,
                "state": State(fsrs_card.state.value).name,
            },
        }

        response = (
            jsonify(response_data),
            201,
        )
        logger.info(response_data)
        return response

    @app.route("/api/get_card", methods=["GET"])
    def get_card():
        """
        获取待复习卡片接口
        ---
        请求方法: GET
        查询参数:
          - grade: string 必填，年级分类，"all"表示所有
          - subject: string 必填，学科分类，"all"表示所有
          - class_name: string 必填，班级名称，"all"表示所有

        响应结构:
        成功(200):
        {
          "id": 卡片ID,
          "question": 问题内容,
          "answer": 答案内容,
          "due": 到期时间,
          "fsrs_status": {"stability", "difficulty", "state", "retrievability"}
        }
        未找到(404):
        {"message": "当前没有需要复习的卡片"}
        """
        logger.info(dumps(request.args))
        required_params = ["grade", "subject", "class_name"]
        args = request.args
        if not all(param in args for param in required_params):
            return jsonify({"error": "缺少查询参数: grade, subject 或 class_name"}), 400

        now = datetime.now(timezone.utc)
        query = Card.query.filter(Card.due <= now)

        if args["grade"] != "all":
            query = query.filter(Card.grade == args["grade"])
        if args["subject"] != "all":
            query = query.filter(Card.subject == args["subject"])
        if args["class_name"] != "all":
            query = query.filter(Card.class_name == args["class_name"])

        card = query.order_by(Card.due.asc()).first()
        card_count = query.count()

        if card:
            review_history = [
                {
                    "time": log.review_time.isoformat(),
                    "rating": log.rating,
                    "feedback": log.feedback,
                }
                for log in ReviewLog.query.filter_by(card_id=card.id).all()
            ]
            response = {
                "id": card.id,
                "question": card.question,
                "answer": card.answer,
                "due": card.due.isoformat(),
                "fsrs_status": {
                    "stability": card.stability,
                    "difficulty": card.difficulty,
                    "state": State(card.state).name,
                    "retrievability": f"{card.to_fsrs().get_retrievability()*100:.1f}%",
                    "review_history": review_history,
                },
                "create_time": card.create_time.isoformat(),  # 返回创建时间
                "card_count": card_count,  # 返回当前班级的卡片数量
            }
            logger.info(response)
            return (
                jsonify(response),
                200,
            )
        logger.info(jsonify({"message": "当前没有需要复习的卡片"}))
        return jsonify({"message": "当前没有需要复习的卡片"}), 204

    @app.route("/api/list_cards", methods=["GET"])
    def list_cards():
        """
        分页查询卡片列表接口
        ---
        请求方法: GET
        查询参数:
          - grade: string 可选，年级过滤，"all"表示所有
          - subject: string 可选，学科过滤,"all"表示所有
          - class_name: string 可选，班级过滤，"all"表示所有
          - date: string 可选，日期过滤(today/tomorrow)

        响应结构:
        成功(200):
        {
          "cards": [{"id", "grade", "subject", "class_name", "question", "last_review", "next_review"}]
        }
        """
        args = request.args
        logger.info(dumps(args))

        query = Card.query

        if "grade" in args and args["grade"] != "all":
            query = query.filter(Card.grade == args["grade"])
        if "subject" in args and args["subject"] != "all":
            query = query.filter(Card.subject == args["subject"])
        if "class_name" in args and args["class_name"] != "all":
            query = query.filter(Card.class_name == args["class_name"])

        # 日期筛选逻辑
        if "date" in args:
            now = datetime.now(timezone.utc)
            if args["date"] == "today":
                end_of_day = datetime(
                    now.year, now.month, now.day, 23, 59, 59, tzinfo=timezone.utc
                )
                query = query.filter(Card.due <= end_of_day)
            elif args["date"] == "tomorrow":
                tomorrow = now + timedelta(days=1)
                start_of_tomorrow = datetime(
                    tomorrow.year,
                    tomorrow.month,
                    tomorrow.day,
                    0,
                    0,
                    0,
                    tzinfo=timezone.utc,
                )
                end_of_tomorrow = datetime(
                    tomorrow.year,
                    tomorrow.month,
                    tomorrow.day,
                    23,
                    59,
                    59,
                    tzinfo=timezone.utc,
                )
                query = query.filter(
                    Card.due >= start_of_tomorrow, Card.due <= end_of_tomorrow
                )
        # 排序逻辑

        if args.get("sort_by_due_value") == "true":
            query = query.order_by(Card.due.asc())
        else:
            query = query.order_by(
                Card.subject.asc(),
                Card.grade.asc(),
                Card.class_name.asc(),
                Card.question.asc(),
            )
        cards = query.all()
        response = {
            "cards": [
                {
                    "id": card.id,
                    "grade": card.grade,
                    "subject": card.subject,
                    "class_name": card.class_name,
                    "question": card.question,
                    "answer": card.answer,
                    "last_review": (
                        card.last_review.isoformat() if card.last_review else None
                    ),
                    "next_review": card.due.isoformat(),
                    "create_time": card.create_time.isoformat(),
                }
                for card in cards
            ]
        }
        return (
            jsonify(response),
            200,
        )

    @app.route("/api/review", methods=["POST"])
    def review_card():
        """
        提交复习结果接口
        ---
        请求方法: POST
        请求体参数:
          - card_id: int 必填，卡片ID
          - rating: int 必填，评分（1-4）
          - feedback: string 可选，用户反馈

        响应结构:
        成功(200):
        {
          "card_id": 卡片ID,
          "new_due": 新到期时间,
          "review_history": 复习历史记录
        }
        错误(400):
        {"error": "需要提供有效的card_id和评分"}
        卡片不存在(404):
        {"error": "卡片不存在"}
        """

        data = request.json
        logger.info(dumps(data))
        card_id = data.get("card_id")
        rating = data.get("rating")

        if not card_id or rating not in (1, 2, 3, 4):
            return jsonify({"error": "需要提供有效的card_id和评分(1-4)"}), 400

        card = Card.query.get(card_id)
        if not card:
            return jsonify({"error": "卡片不存在"}), 404

        fsrs_card = card.to_fsrs()

        new_fsrs_card, review_log = scheduler.review_card(
            fsrs_card,
            rating,
            review_datetime=(
                datetime.now(tz=timezone.utc) - timedelta(days=1)
                if data.get("yesterday")
                else datetime.now(tz=timezone.utc)
            ),
        )

        # 添加复习记录
        new_log = ReviewLog(
            card_id=card_id, rating=rating, feedback=data.get("feedback")  # 反馈字段
        )
        db.session.add(new_log)

        # 更新卡片状态
        card.due = new_fsrs_card.due
        card.stability = new_fsrs_card.stability
        card.difficulty = new_fsrs_card.difficulty
        card.state = 2 if rating != 1 else 3
        card.last_review = review_log.review_datetime

        db.session.commit()

        logger.info(dumps({"card_id": card.id, "new_due": card.due.isoformat()}))
        # 如果 due 在今天 00:00 到明天 23:59 之间，发送一次 rating=3 的请求，并直接返回它的响应
        now = datetime.now(timezone.utc)
        today_start = datetime(now.year, now.month, now.day, 0, 0, 0, tzinfo=timezone.utc)
        tomorrow_end = today_start + timedelta(days=1, hours=23, minutes=59, seconds=59)

        if (
            today_start <= card.due.replace(tzinfo=timezone.utc) <= tomorrow_end
            and rating != 1
        ):
            try:
                url = request.url  # 当前请求的完整 URL
                payload = {"card_id": card_id, "rating": 3}
                headers = {"Content-Type": "application/json"}
                response = requests.post(url, json=payload, headers=headers)
                return response.json(), response.status_code
            except Exception as e:
                logger.error(f"自动复习请求失败: {str(e)}")
                # 如果额外的请求失败，则返回原始更新的信息
                return (
                    jsonify(
                        {
                            "card_id": card.id,
                            "new_due": card.due.isoformat(),
                        }
                    ),
                    200,
                )

        # 如果 due 不在指定范围内，正常返回
        return (
            jsonify(
                {
                    "card_id": card.id,
                    "new_due": card.due.isoformat(),
                }
            ),
            200,
        )

    @app.route("/api/delete", methods=["DELETE"])
    def delete_card():
        """
        删除卡片及其所有记录接口
        ---
        请求方法: DELETE
        请求体参数:
          - id: int 必填，卡片ID

        响应结构:
        成功(200):
        {
          "message": "卡片及记录删除成功",
          "deleted_card": 删除的卡片ID,
          "deleted_logs": 删除的复习记录数
        }
        错误(400):
        {"error": "需要提供有效的卡片ID"}
        卡片不存在(404):
        {"error": "卡片不存在"}
        """
        data = request.json
        card_id = data.get("id")

        if not card_id:
            return jsonify({"error": "需要提供有效的卡片ID"}), 400

        # 先删除复习记录
        deleted_logs = ReviewLog.query.filter_by(card_id=card_id).delete()
        # 应包裹在事务中
        try:
            with db.session.begin_nested():
                deleted_logs = ReviewLog.query.filter_by(card_id=card_id).delete()
                card = Card.query.get(card_id)
                db.session.delete(card)
            db.session.commit()
        except:
            db.session.rollback()
        response = jsonify(
            {
                "message": "卡片及记录删除成功",
                "deleted_card": card_id,
                "deleted_logs": deleted_logs,
            }
        )
        logger.info("DELETE CARD" + str(card_id))
        return (response, 200)

    @app.route("/")
    @app.route("/add")
    @app.route("/list")
    @app.route("/review/classic")
    @app.route("/review/list")
    @app.route("/statistics")
    def serve_vue_app(path=""):
        return send_from_directory(app.static_folder, "index.html")